---
title: Tags Input
description: Using the tags input machine in your project.
package: "@zag-js/tags-input"
---

Tag inputs render tags inside an input, followed by an actual text input. By
default, tags are added when text is typed in the input field and the `Enter` or
`Comma` key is pressed. Throughout the interaction, DOM focus remains on the
input element.

<Resources pkg="@zag-js/tags-input" />

<Showcase id="TagsInput" />

**Features**

- Typing in the input and pressing enter will add new items
- Clear button to reset all tags values
- Add tags by pasting into the input
- Delete tags on backspace
- Edit tags after creation
- Limit the number of tags
- Navigate tags with keyboard
- Custom validation to accept/reject tags

## Installation

To use the tags input machine in your project, run the following command in your
command line:

<CodeSnippet id="tags-input/installation.mdx" />

## Anatomy

To set up the tags input correctly, you'll need to understand its anatomy and
how we name its parts.

> Each part includes a `data-part` attribute to help identify them in the DOM.

<Anatomy id="tags-input" />

## Usage

First, import the tags input package into your project

```jsx
import * as tagsInput from "@zag-js/tags-input"
```

The tags input package exports two key functions:

- `machine` — The state machine logic for the tags input widget.
- `connect` — The function that translates the machine's state to JSX attributes
  and event handlers.

> You'll also need to provide a unique `id` to the `useMachine` hook. This is
> used to ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the
tags input machine in your project 🔥

<CodeSnippet id="tags-input/usage.mdx" />

### Navigating and Editing tags

When the input has an empty value or the caret is at the start position, the
tags can be selected by using the arrow left and arrow right keys. When "visual"
focus in on any tag:

- Pressing `Enter` or double clicking on the tag will put the it in edit mode,
  allowing the user change its value and press `Enter` to commit the changes.
- Pressing `Delete` or `Backspace` will delete the tag that has "visual" focus.

### Setting the initial tags

To set the initial tag values, pass the `defaultValue` property in the machine's
context.

```jsx {2}
const service = useMachine(tagsInput.machine, {
  defaultValue: ["React", "Redux", "TypeScript"],
})
```

### Controlled tags input

To control the tags input programmatically, pass the `value` and `onValueChange`
properties to the machine function.

<CodeSnippet id="tags-input/controlled.mdx" />

### Removing all tags

The tags input will remove all tags when the clear button is clicked. To remove
all tags, use the provided `clearButtonProps` function from the `api`.

```jsx {4}
//...
<div {...api.getControlProps()}>
  <input {...api.getInputProps()} />
  <button {...api.getClearButtonProps()} />
</div>
//...
```

To programmatically remove all tags, use the `api.clearAll()` method that's
available in the `connect`.

### Usage within forms

The tags input works when placed within a form and the form is submitted. We
achieve this by:

- ensuring we emit the input event as the value changes.
- adding a `name` and `value` attribute to a hidden input so the tags can be
  accessed in the `FormData`.

To get this feature working you need to pass a `name` option to the context and
render the `hiddenInput` element.

```jsx {2}
const service = useMachine(tagsInput.machine, {
  name: "tags",
  defaultValue: ["React", "Redux", "TypeScript"],
})
```

### Limiting the number of tags

To limit the number of tags within the component, you can set the `max` property
to the limit you want. The default value is `Infinity`.

When the tag reaches the limit, new tags cannot be added except the
`allowOverflow` option is passed to the context.

```jsx {2-3}
const service = useMachine(tagsInput.machine, {
  max: 10,
  allowOverflow: true,
})
```

### Validating Tags

Before a tag is added, the machine provides a `validate` function you can use to
determine whether to accept or reject a tag.

A common use-case for validating tags is preventing duplicates or validating the
data type.

```jsx {2-3}
const service = useMachine(tagsInput.machine, {
  validate(details) {
    return !details.values.includes(details.inputValue)
  },
})
```

### Blur behavior

When the tags input is blurred, you can configure the action the machine should
take by passing the `blurBehavior` option to the context.

- `"add"` — Adds the tag to the list of tags.
- `"clear"` — Clears the tags input value.

```jsx {2}
const service = useMachine(tagsInput.machine, {
  blurBehavior: "add",
})
```

### Paste behavior

To add a tag when a arbitrary value is pasted in the input element, pass the
`addOnPaste` option.

When a value is pasted, the machine will:

- check if the value is a valid tag based on the `validate` option
- split the value by the `delimiter` option passed

```jsx {2}
const service = useMachine(tagsInput.machine, {
  addOnPaste: true,
})
```

### Disable tag editing

by default the tags can be edited by double clicking on the tag or focusing on
them and pressing `Enter`. To disable this behavior, pass the
`allowEditTag: false`

```jsx {2}
const service = useMachine(tagsInput.machine, {
  allowEditTag: false,
})
```

### Listening for events

During the lifetime of the tags input interaction, here's a list of events we
emit:

- `onValueChange` — invoked when the tag value changes.
- `onHighlightChange` — invoked when a tag has visual focus.
- `onValueInvalid` — invoked when the max tag count is reached or the `validate`
  function returns `false`.

```jsx
const service = useMachine(tagsInput.machine, {
  onValueChange(details) {
    // details => { value: string[] }
    console.log("tags changed to:", details.value)
  },
  onHighlightChange(details) {
    // details => { value: string }
    console.log("highlighted tag:", details.value)
  },
  onValueInvalid(details) {
    console.log("Invalid!", details.reason)
  },
})
```

## Styling guide

Earlier, we mentioned that each accordion part has a `data-part` attribute added
to them to select and style them in the DOM.

### Focused state

The combobox input is focused when the user clicks on the input element. In this
focused state, the root, label, input.

```css
[data-part="root"][data-focus] {
  /* styles for root focus state */
}

[data-part="label"][data-focus] {
  /* styles for label focus state */
}

[data-part="input"]:focus {
  /* styles for input focus state */
}
```

### Invalid state

When the tags input is invalid by setting the `invalid: true` in the machine's
context, the `data-invalid` attribute is set on the root, input, control, and
label.

```css
[data-part="root"][data-invalid] {
  /* styles for invalid state for root */
}

[data-part="label"][data-invalid] {
  /*  styles for invalid state for label */
}

[data-part="input"][data-invalid] {
  /*  styles for invalid state for input */
}
```

### Disabled state

When the tags input is disabled by setting the `disabled: true` in the machine's
context, the `data-disabled` attribute is set on the root, input, control and
label.

```css
[data-part="root"][data-disabled] {
  /* styles for disabled state for root */
}

[data-part="label"][data-disabled] {
  /* styles for disabled state for label */
}

[data-part="input"][data-disabled] {
  /* styles for disabled state for input */
}

[data-part="control"][data-disabled] {
  /* styles for disabled state for control */
}
```

When a tag is disabled, the `data-disabled` attribute is set on the tag.

```css
[data-part="item-preview"][data-disabled] {
  /* styles for disabled tag  */
}
```

### Highlighted state

When a tag is highlighted via the keyboard navigation or pointer hover, a
`data-highlighted` attribute is set on the tag.

```css
[data-part="item-preview"][data-highlighted] {
  /* styles for visual focus */
}
```

### Readonly state

When the tags input is in its readonly state, the `data-readonly` attribute is
set on the root, label, input and control.

```css
[data-part="root"][data-readonly] {
  /* styles for readonly for root */
}

[data-part="control"][data-readonly] {
  /* styles for readonly for control */
}

[data-part="input"][data-readonly] {
  /* styles for readonly for input  */
}

[data-part="label"][data-readonly] {
  /* styles for readonly for label */
}
```

## Methods and Properties

### Machine Context

The tags input machine exposes the following context properties:

<ContextTable name="tags-input" />

### Machine API

The tags input `api` exposes the following methods:

<ApiTable name="tags-input" />

### Data Attributes

<DataAttrTable name="tags-input" />

## Accessibility

### Keyboard Interactions

<KeyboardTable name="tags-input" />
